package ast

import (
	"fmt"

	"gitee.com/u-language/u-language/ucom/astdata"
	"gitee.com/u-language/u-language/ucom/enum"
	"gitee.com/u-language/u-language/ucom/errcode"
	"gitee.com/u-language/u-language/ucom/internal/errutil"
	"gitee.com/u-language/u-language/ucom/internal/utils"
	"gitee.com/u-language/u-language/ucom/lex"

	"github.com/huandu/go-clone"
)

// isHaveType 是否有类型参数
// decl==可能使用类型参数的列表 form==实例化列表 typ==类型参数列表
// decl=类型参数列表 form=实例化列表
func isHaveType(decl []astdata.NameAndType, form []astdata.Typ, typ []astdata.NameAndType) bool {
	if len(typ) != len(form) {
		return true
	}
	for i := 0; i < len(decl); i++ {
		if g, ok := decl[i].Type.(*GenericInstantiation); ok && isUseType(g.ActualType, typ) { //如果是泛型实例化且使用了类型参数
			continue
		}
		typname := utils.Ret_no_lea(decl[i].Type.Typ())
		for j := 0; j < len(typ); j++ {
			if typname == typ[j].Name { //如果是类型是 泛型占位符 ，替换为实际类型
				return true
			}
		}
	}
	return false
}

// isHaveType 是否使用类型参数
// form==实际使用类型列表 typ==类型参数列表
func isUseType(form []astdata.Typ, typ []astdata.NameAndType) bool {
	for i := 0; i < len(form); i++ {
		if g, ok := form[i].(*GenericInstantiation); ok { //如果是泛型实例化
			if isUseType(g.ActualType, typ) {
				return true
			}
			continue
		}
		typname := utils.Ret_no_lea(form[i].Typ())
		for j := 0; j < len(typ); j++ {
			if typname == typ[j].Name { //如果是类型是 泛型占位符 ，替换为实际类型
				return true
			}
		}
	}
	return false
}

// parserGenericInstantiation 解析泛型实例化
// 假设len(tks)==2 && tks[0].TYPE==lex.NAME&& tks[1].TYPE == lex.TokenWithBrackets
func parserGenericInstantiation(t *Tree, tks []lex.Token, line *lex.Line, err errcode.ErrCode, FuncInfo *FuncInfo) *GenericInstantiation {
	s := ret_middle_str(tks[1].Value)
	list := check_from_list(s)
	llen := len(list)
	if llen == 0 { //如果泛型实例化列表为空
		t.Panic(line, nil, err, errcode.GenericInstantiationEmpty)
		return nil
	}
	var ret = new(GenericInstantiation)
	ret.BaseName = parserTypeName(t, line, &tks[0], err, FuncInfo)
	ret.ActualType = make([]astdata.Typ, llen)
	for i := 0; i < llen; i++ {
		token := lex_scan(t, list[i], line)
		if len(token) != 1 { //如果不是类型 T
			t.Panic(line, nil, err, errcode.UnknownType)
			return nil
		}
		ret.ActualType[i] = parserTypeName(t, line, &token[0], err, FuncInfo)
	}
	ret.LineNum, ret.FileName = line.Linenum, t.Filename
	return ret
}

// genericReplaceNode 替换一个节点的类型参数为实际类型
//
//	typ==类型参数列表 form==实例化列表
func genericReplaceNode(findTree func(string) *Tree, n Node, typ []astdata.NameAndType, form []astdata.Typ, t *Tree, sbt *Sbt) Node {
	switch n := n.(type) {
	case *VarNode:
		if g, ok := n.TYPE.(*GenericInstantiation); ok { //如果类型属于泛型实例化
			ret := *n
			copy_g := g.Copy().(*GenericInstantiation)
			ret.TYPE = copy_g
			genericReplace2(copy_g.ActualType, form, typ)
			info := sbt.Have(ret.Name)
			if vinfo, ok := info.Info.(VarInfoSbt); ok {
				vinfo.Type = ret.TYPE
				sbt.store(ret.Name, enum.SymbolVar, vinfo)
			} else {
				sbt.store(ret.Name, enum.SymbolNoParameVar, &ret)
			}
			return &ret
		}
	case *ASSIGNNode:
		v := clone.Clone(n).(*ASSIGNNode)
		v.Dest = genericReplaceExpr(findTree, v.Dest, typ, form, t, sbt)
		v.Src = genericReplaceExpr(findTree, v.Src, typ, form, t, sbt)
		return v
	case *IfNode:
		v := clone.Clone(n).(*IfNode)
		v.BoolExpr = genericReplaceExpr(findTree, v.BoolExpr, typ, form, t, sbt)
		return v
	case *ElseNode:
		v := clone.Clone(n).(*ElseNode)
		v.BoolExpr = genericReplaceExpr(findTree, v.BoolExpr, typ, form, t, sbt)
		return v
	case *ForNode:
		v := clone.Clone(n).(*ForNode)
		v.InitStmt = genericReplaceNode(findTree, v.InitStmt, typ, form, t, sbt)
		v.BoolExpr = genericReplaceExpr(findTree, v.BoolExpr, typ, form, t, sbt)
		v.EndStmt = genericReplaceNode(findTree, v.EndStmt, typ, form, t, sbt)
		return v
	case *ReturnNode:
		v := clone.Clone(n).(*ReturnNode)
		v.RetValue = genericReplaceExpr(findTree, v.RetValue, typ, form, t, sbt)
		return v
	case *ConstNode:
		if g, ok := n.TYPE.(*GenericInstantiation); ok { //如果类型属于泛型实例化
			ret := *n
			copy_g := g.Copy().(*GenericInstantiation)
			ret.TYPE = copy_g
			genericReplace2(copy_g.ActualType, form, typ)
			sbt.store(ret.Name, enum.SymbolConst, &ret)
			return &ret
		}
	case *SelfOpStmt:
		v := clone.Clone(n).(*SelfOpStmt)
		v.Dest = genericReplaceExpr(findTree, v.Dest, typ, form, t, sbt)
		return v
	case *SwitchNode:
		v := clone.Clone(n).(*SwitchNode)
		v.Expr = genericReplaceExpr(findTree, v.Expr, typ, form, t, sbt)
		return v
	case *CaseNode:
		v := clone.Clone(n).(*CaseNode)
		v.Expr = genericReplaceExpr(findTree, v.Expr, typ, form, t, sbt)
		return v
	case *AutoFreeNode:
		v := clone.Clone(n).(*AutoFreeNode)
		v.Expr = genericReplaceExpr(findTree, v.Expr, typ, form, t, sbt)
		return v
	case Expr:
		return genericReplaceExpr(findTree, n, typ, form, t, sbt)
	case *DefaultNode, RbraceNode, *GotoStmt, *LabelNode, BreakStmt, ContinueStmt, *StructDecl, *EnumDecl:
	default:
		panic(errutil.NewErr2(errutil.CompileErr, fmt.Sprintf("未知的节点：%+v", n)))
	}
	return n
}

// genericReplaceExpr 替换一个表达式节点的类型参数为实际类型
//
//	typ==类型参数列表 form==实例化列表
func genericReplaceExpr(findTree func(string) *Tree, n Expr, typ []astdata.NameAndType, form []astdata.Typ, t *Tree, sbt *Sbt) Expr {
	switch v := n.(type) {
	case *OpExpr:
		v = clone.Clone(v).(*OpExpr)
		v.Src1 = genericReplaceExpr(findTree, v.Src1, typ, form, t, sbt)
		v.Src2 = genericReplaceExpr(findTree, v.Src2, typ, form, t, sbt)
		return v
	case *CallNode:
		v = clone.Clone(v).(*CallNode)
		if g, ok := v.FuncName.(*GenericInstantiation); ok {
			g = g.Copy().(*GenericInstantiation)
			g = genericReplaceNode(findTree, g, typ, form, t, sbt).(*GenericInstantiation) //这里复制考虑到泛型函数可能根据类型参数的不同，实例化不同
			name := g.FuncName()
			_, ok := t.GenericTable.have(name)
			if !ok {
				t.GenericTable.add(name, enum.SymbolGenInst, g)
			}
			v.FuncName = g
		}
		for i := 0; i < len(v.Parame); i++ {
			v.Parame[i] = genericReplaceExpr(findTree, v.Parame[i], typ, form, t, sbt)
		}
		return v
	case *IndexExpr:
		v = clone.Clone(v).(*IndexExpr)
		v.Index = genericReplaceExpr(findTree, v.Index, typ, form, t, sbt)
		v.X = genericReplaceExpr(findTree, v.X, typ, form, t, sbt)
		return v
	case *GenericInstantiation:
		v = clone.Clone(v).(*GenericInstantiation)
		genericReplace2(v.ActualType, form, typ)
		Instatination(findTree, t, t.GenInstNodes, v.LineNum, v.BaseName.Typ(), v.ActualType, "")
		return v
	case *Dereference:
		v = clone.Clone(v).(*Dereference)
		v.Value = genericReplaceExpr(findTree, v.Value, typ, form, t, sbt)
		return v
	case *Object, *Objects:
	default:
		panic(errutil.NewErr2(errutil.CompileErr, fmt.Sprintf("未知的节点：%+v", n)))
	}
	return n
}

func Instatination(findTree func(string) *Tree, t *Tree, GenInstNodes *Sbt, LineNum int, Base string, ActualType []astdata.Typ, str string) {
	defer func() {
		if err := recover(); err != nil {
			name, ok := errutil.IsUnknownSymbol(err)
			if ok {
				t.errctx.Panic(t.Filename, LineNum, errcode.NewMsgUnknownSymbol(name), errcode.UnknownSymbol)
				return
			}
			name, ok = errutil.IsUnknownType(err)
			if ok {
				t.errctx.Panic(t.Filename, LineNum, errcode.NewMsgUnknownSymbol(name), errcode.UnknownType)
				return
			}
			panic(err)
		}
	}()
	base_info := t.Sbt.Have(Base)
	switch base_info.Kind {
	case enum.SymbolStruct:
		s := base_info.Info.(*StructDecl)
		t = findTree(s.FileName)
		decl := t.Nodes[s.LineNum-1].(*StructDecl)
		add, err := genericReplaceStruct(decl, ActualType)
		if err != errcode.NoErr {
			t.errctx.Panic(s.FileName, LineNum, nil, err)
			return
		}
		methods_info := add.sbt.Have(add.Name + enum.Method)
		if str != "" {
			add.Name = str
		} else {
			add.Name = add.genName()
		}
		table := methods_info.Info.(MethodTableInfo)
		table.Infos = table.Infos.Copy()
		table.Infos.Range(func(s string, info SymbolInfo) bool { //实例化方法
			method := info.Info.(*MethodNode)
			name := astdata.Generate_method_symbol(method.Typ, method.Name)
			Instatination(findTree, t, t.GenInstNodes, method.FuncInfo.LineNum, name, ActualType, "")
			return true
		})
		t.Sbt.store(add.Name, enum.SymbolStruct, add) //记录实例化符号到符号报表
		t.Sbt.store(add.Name+enum.Method, enum.SymbolMethodTable, table)
		t.GenInstNodes.store(add.Name, enum.SymbolRemoveGenerics, RemoveGenericsInfo{FileName: s.FileName, Nodes: []Node{add}, LineNum: s.LineNum})
	case enum.SymbolFunc:
		s := base_info.Info.(*FuncInfo)
		t = findTree(s.FileName)
		decl := t.Nodes[s.LineNum-1].(*FuncNode)
		nodes := make([]Node, decl.Right-decl.Left+2)
		add, err := genericReplaceFunc(decl, ActualType)
		if err != errcode.NoErr {
			t.errctx.Panic(s.FileName, LineNum, nil, err)
			return
		}
		if str != "" {
			add.Name = str
		} else {
			_, ok := t.Sbt.have(add.genName())
			if ok {
				add.Name = add.genName()
			} else { //如果已经被实例化
				return
			}
		}
		t.Sbt.store(add.Name, enum.SymbolFunc, add.FuncInfo)
		nodes[0] = add
		for index, i := decl.Left, 1; index <= decl.Right; index, i = index+1, i+1 {
			n := genericReplaceNode(findTree, t.Nodes[index], decl.TypeParame, ActualType, t, add.Sbt)
			nodes[i] = n
		}
		t.GenInstNodes.store(add.Name, enum.SymbolRemoveGenerics, RemoveGenericsInfo{FileName: s.FileName, Nodes: nodes, LineNum: s.LineNum})
	case enum.SymbolMethod:
		s := base_info.Info.(*MethodNode)
		t = findTree(s.FileName)
		decl := t.Nodes[s.FuncInfo.LineNum-1].(*MethodNode)
		nodes := make([]Node, decl.Right-decl.Left+2)
		add, err := genericReplaceMethod(decl, ActualType)
		if err != errcode.NoErr {
			t.errctx.Panic(s.FileName, LineNum, nil, err)
			return
		}
		if str != "" {
			add.Name = str
		} else {
			name := astdata.Generate_method_symbol(add.Parame[0].Type.Typ(), add.Name)
			add.Typ = add.Parame[0].Type.Typ()
			_, ok := t.Sbt.have(name)
			if !ok {
			} else { //如果已经被实例化
				return
			}
		}
		t.Sbt.store(add.Name, enum.SymbolMethod, add)
		nodes[0] = add
		for index, i := decl.Left, 1; index <= decl.Right; index, i = index+1, i+1 {
			n := genericReplaceNode(findTree, t.Nodes[index], decl.TypeParame, ActualType, t, add.Sbt)
			nodes[i] = n
		}
		t.GenInstNodes.store(str, enum.SymbolRemoveGenerics, RemoveGenericsInfo{FileName: s.FileName, Nodes: nodes, LineNum: s.LineNum})
	}
}

// genericReplaceStruct 替换结构体的泛型占位符为实际类型
func genericReplaceStruct(decl *StructDecl, form []astdata.Typ) (*StructDecl, errcode.ErrCode) {
	if len(decl.TypeParame) != len(form) {
		return nil, errcode.UnequlaNumOfGen
	}
	ret := *decl
	ret.FieldTable = copyNameAndTyp(ret.FieldTable)
	genericReplace(ret.FieldTable, form, decl.TypeParame)
	ret.TypeParame = nil
	return &ret, errcode.NoErr
}

// genericReplaceFunc 替换函数的泛型占位符为实际类型
func genericReplaceFunc(f *FuncNode, form []astdata.Typ) (*FuncNode, errcode.ErrCode) {
	if len(f.TypeParame) != len(form) {
		return nil, errcode.UnequlaNumOfGen
	}
	ret := *f
	ret.Sbt = ret.Sbt.Copy()
	ret.FuncInfo = ret.FuncInfo.Copy()
	genericReplace(ret.Parame, form, f.TypeParame)
	for _, v := range ret.Parame {
		ret.Sbt.store(v.Name, enum.SymbolVar, NewVarInfoSbt(v.Name, v.Type, true, f.LineNum, f.FileName))
	}
	genericReplace(ret.RetValue, form, f.TypeParame)
	ret.TypeParame = nil
	return &ret, errcode.NoErr
}

// genericReplaceMethod 替换方法的泛型占位符为实际类型
func genericReplaceMethod(f *MethodNode, form []astdata.Typ) (*MethodNode, errcode.ErrCode) {
	if len(f.FuncInfo.TypeParame) != len(form) {
		return nil, errcode.UnequlaNumOfGen
	}
	ret := *f
	ret.Sbt = ret.Sbt.Copy()
	ret.FuncInfo = ret.FuncInfo.Copy()
	genericReplace(ret.FuncInfo.Parame, form, f.FuncInfo.TypeParame)
	for _, v := range ret.Parame {
		ret.Sbt.store(v.Name, enum.SymbolVar, NewVarInfoSbt(v.Name, v.Type, true, f.LineNum, f.FileName))
	}
	genericReplace(ret.FuncInfo.RetValue, form, f.FuncInfo.TypeParame)
	ret.TypeParame = nil
	return &ret, errcode.NoErr
}

// genericReplace 替换泛型占位符为实际类型
// decl==可能使用类型参数的列表 form==实例化列表 typ==类型参数列表
func genericReplace(decl []astdata.NameAndType, form []astdata.Typ, typ []astdata.NameAndType) {
	for i := 0; i < len(decl); i++ {
		if g, ok := decl[i].Type.(*GenericInstantiation); ok && isUseType(g.ActualType, typ) { //如果是泛型实例化且使用了泛型
			genericReplace2(g.ActualType, form, typ)
			continue
		}
		typname, ilea := utils.Ret_type_no_lea(decl[i].Type.Typ())
		genCas(typname, &decl[i].Type, ilea, form, typ)
	}
}

// genericReplace2 替换泛型占位符为实际类型
// decl==可能使用类型参数的类型列表 form==实例化列表 typ==类型参数列表
func genericReplace2(decl []astdata.Typ, form []astdata.Typ, typ []astdata.NameAndType) {
	for i := 0; i < len(decl); i++ {
		if g, ok := decl[i].(*GenericInstantiation); ok && isUseType(g.ActualType, typ) { //如果是泛型实例化且使用了泛型
			genericReplace2(g.ActualType, form, typ)
			continue
		}
		typname, ilea := utils.Ret_type_no_lea(decl[i].Typ())
		genCas(typname, &decl[i], ilea, form, typ)
	}
}

// genCas 如果使用了类型参数则替换为实际类型
// decl==可能使用类型参数的类型 form==实例化列表 typ==类型参数列表
func genCas(typname string, decl *astdata.Typ, ilea int, form []astdata.Typ, typ []astdata.NameAndType) {
	for j := 0; j < len(typ); j++ {
		if typname == typ[j].Name { //如果是类型是 泛型占位符 ，替换为实际类型
			if ilea == 0 {
				*decl = form[j]
				break
			} else {
				c := form[j].Copy()
				c.SetLea(ilea)
				*decl = c
				break
			}
		}
	}
}

func generateGenInst(t *Tree, findTree func(string) *Tree) {
	t.GenericTable.Range(func(str string, info SymbolInfo) bool {
		i := info.Info.(*GenericInstantiation)
		t := findTree(i.FileName)
		Instatination(findTree, t, t.GenInstNodes, i.LineNum, i.BaseName.Typ(), i.ActualType, str)
		return true
	})
}
